package com.xiaoma.common.utils


typealias FailureWorker = (String?, Throwable?) -> Unit

typealias  SuccessWorker<T> = (T) -> Unit

typealias  LoadingWorker = (String?) -> Unit

typealias  DataWorker<T> = (T) -> Unit

typealias  EventWorker = () -> Unit
class VmEvent<T> private constructor(
    val type: Type,
    val data: T? = null,
    private val msg: String? = null,
    private val exception: Throwable? = null,
    var consumed: Boolean = false
) {

    companion object {
        fun <T> data(data: T) = VmEvent(Type.DATA, data)

        fun <T> event() = VmEvent<T>(Type.EVENT)

        fun <T> loading(data: T? = null, msg: String? = null) = VmEvent(Type.LOADING, data, msg)

        fun <T> success(data: T) = VmEvent(Type.SUCCESS, data)

        fun <T> failure(msg: String? = null, e: Throwable? = null, data: T? = null) =
            VmEvent(Type.FAILURE, data, msg = msg, exception = e)
    }


    /** 当数据更新时触发. */
    fun onData(repeatable: Boolean = false, worker: DataWorker<T>): VmEvent<T> {
        if (Type.DATA != type) return this

        if (consumed) return this
        if (!repeatable) consumed = true

        data?.let(worker)
        return this
    }

    /** 当事件发生时触发. */
    fun onEvent(repeatable: Boolean = false, worker: EventWorker): VmEvent<T> {
        if (Type.EVENT != type) return this

        if (consumed) return this
        if (!repeatable) consumed = true

        worker()
        return this
    }

    /** 当事件开始加载时触发. */
    fun onLoading(repeatable: Boolean = false, worker: LoadingWorker): VmEvent<T> {
        if (Type.LOADING != type) return this

        if (consumed) return this
        if (!repeatable) consumed = true

        worker(msg)
        return this
    }

    /** 当事件成功是触发. */
    fun onSuccess(repeatable: Boolean = false, worker: SuccessWorker<T>): VmEvent<T> {
        if (Type.SUCCESS != type) return this

        if (consumed) return this
        if (!repeatable) consumed = true
        data?.let(worker)
        return this
    }

    /** 当事件失败时触发. */
    fun onFailure(repeatable: Boolean = false, worker: FailureWorker): VmEvent<T> {
        if (Type.FAILURE != type) return this

        if (consumed) return this
        if (!repeatable) consumed = true

        worker(msg, exception)
        return this
    }


    enum class Type {
        DATA,
        EVENT,

        LOADING,
        SUCCESS,
        FAILURE,
    }
}